package gate

import (
	"base"
	"center_server/logic/center/api"
	"center_server/logic/gate/api"
	"center_server/logic/gate/event"
	. "center_server/logic/internal"
	"center_server/logic/login/api"
	"center_server/logic/player/api"
	"center_server/model"
	"emma/errors"
	"leaf/gate"
	"proto/base"
	"proto/server/center"
	"proto/server/gate"
	"proto/server/login"
)

type gateSystem struct {
	servers map[base.AgentId]*gateServer
}

var system = new(gateSystem)

func init() {
	system.servers = make(map[base.AgentId]*gateServer)
}

func init() {
	gate_api.GetClient = system.GetClient
	gate_api.RemoveClient = system.RemoveClient
	gate_api.Logout = system.Logout
	gate_api.OnLogin = system.OnLogin
	gate_api.InnerAddrs = system.InnerAddrs
}

func init() {
	Skeleton.AfterInit(func() {
		center_api.RegisterHandler(proto_base.Server_GateServer, system)
	})
}

func (*gateSystem) OnRegister(id base.AgentId, agent gate.Agent, data []byte) (result interface{}) {
	server := new(gateServer)
	server.Agent = agent
	server.id = id
	server.innerAddr = string(data)
	server.clients = make(map[base.ClientId]*model.Client)
	system.servers[id] = server

	agent.SetUserData(server)

	Event.Notify(gate_event.OnRegister, server.id, server.innerAddr)

	return
}

func (*gateSystem) OnClose(id base.AgentId, agent gate.Agent) {
	server, exists := system.servers[id]
	if !exists {
		return
	}

	delete(system.servers, id)
	agent.SetUserData(nil)

	Event.Notify(gate_event.OnClose, server.id, server.innerAddr)
}

func (*gateSystem) GetClient(gateId base.AgentId, clientId base.ClientId) (result *model.Client, exists bool) {
	var server *gateServer
	server, exists = system.servers[gateId]
	if !exists {
		return
	}

	result, exists = server.clients[clientId]

	return
}

func (*gateSystem) RemoveClient(gateId base.AgentId, clientId base.ClientId) {
	server, exists := system.servers[gateId]
	if !exists {
		return
	}

	delete(server.clients, clientId)
}

func (*gateSystem) Logout(gateId base.AgentId, clientId base.ClientId, reason proto_base.LogoutReason) {
	server, exists := system.servers[gateId]
	if !exists {
		return
	}

	client, exists := server.clients[clientId]
	if !exists {
		return
	}

	if player := client.Player(); player != nil {
		msg := new(proto_server_gate.OnLogout)
		msg.Reason = reason
		msg.PlayerId = player.Id().String()
		server.WriteMsg(msg)

		player_api.Remove(player.Id())
	}

	system.logout(server, clientId)
}

func (*gateSystem) OnLogin(gateId base.AgentId, clientId base.ClientId, msg *proto_server_gate.OnLogin) {
	server, exists := system.servers[gateId]
	if !exists {
		return
	}

	if _, exists := server.clients[clientId]; !exists {
		return
	}

	msg.ClientId = clientId
	server.WriteMsg(msg)
}

func (*gateSystem) InnerAddrs() (result map[base.AgentId]string) {
	result = make(map[base.AgentId]string)
	for _, server := range system.servers {
		result[server.id] = server.innerAddr
	}

	return
}

func (*gateSystem) login(server *gateServer, msg *proto_server_center.Login) (err error) {
	clientId := base.ClientId(msg.ClientId)
	client, exists := server.clients[clientId]
	if exists {
		status := client.Status()
		switch status {
		case model.Client_NoLoginStatus:
			code := int(proto_base.ErrorCode_PlayerIsLogingIn)
			err = errors.New(code, "玩家正在登录模块处理")
			return
		case model.Client_PlayStatus:
			code := int(proto_base.ErrorCode_NoRepeatLogin)
			err = errors.New(code, "不允许玩家重复登录")
			return
		default:
			code := int(proto_base.ErrorCode_ServerInternalError)
			err = errors.New(code, "未定义的客户端状态枚举: %v", status)
			return
		}
	} else {
		client = model.NewClient(clientId, server.id)
		server.clients[clientId] = client
	}

	request := new(proto_server_login.Login)
	request.Account = msg.Account
	request.Password = msg.Password
	request.GateId = int32(server.id)
	request.ClientId = msg.ClientId
	err = login_api.Login(request)

	return
}

func (*gateSystem) logout(server *gateServer, clientId base.ClientId) {
	client, exists := server.clients[clientId]
	if !exists {
		return
	}

	client.Clear()
	delete(server.clients, clientId)
}
